/**
 * File Utilities for Chat吉PT/NODA节点 userscript.
 */

/**
 * Updates virtual file system for Monaco editor
 * @param {Object} monacoController - The Monaco controller instance
 * @param {Object} fileDict - Dictionary of files to register with Monaco
 */
export function updateVirtualFileSystem(monacoController, fileDict) {
  const monaco = monacoController.monacoController.monaco;

  // 计算客户端和服务器端文件的数量
  let clientFileCount = 0;
  let serverFileCount = 0;

  for (const key in fileDict) {
    if (fileDict.hasOwnProperty(key)) {
      const { isClient } = fileDict[key];
      if (isClient) {
        clientFileCount++;
      } else {
        serverFileCount++;
      }
    }
  }

  for (const key in fileDict) {
    if (fileDict.hasOwnProperty(key)) {
      const { name, text, isClient } = fileDict[key];
      if (
        (isClient && clientFileCount > 2) ||
        (!isClient && serverFileCount > 2)
      ) {
        // Create and set virtual file
        const fileUri = monaco.Uri.file(`/${name}`);
        let model = monaco.editor.getModel(fileUri);
        if (!model) {
          model = monaco.editor.createModel(text, "javascript", fileUri);
        } else {
          model.setValue(text);
        }
      }
    }
  }
}

/**
 * Gets all file contents from the editor state
 * @param {Object} editorState - The editor state containing the file dictionary
 * @returns {string} - Combined string of all file contents with metadata
 */
export function getAllFileContents(editorState) {
  const fileDict = editorState.fileDict;
  let result = "";

  for (const key in fileDict) {
    if (fileDict.hasOwnProperty(key)) {
      const { name, text, isClient } = fileDict[key];
      result += `文件名: ${name}\n是否客户端: ${isClient}\n内容:\n${text}\n\n`;
    }
  }

  return result;
}

/**
 * Finds functions and classes in code
 * @param {Object} model - The Monaco editor model containing the code
 * @returns {Array} - Array of symbols (functions, classes) found in the code
 */
export function findSymbolsInCode(model) {
  const text = model.getValue();
  const result = [];

  // Match different function declarations using regex
  const patterns = [
    {
      regex: /function\s+(\w+)\s*\([^)]*\)\s*{/g,
      kind: "Function",
    },
    {
      regex: /(?:const|let|var)\s+(\w+)\s*=\s*function\s*\([^)]*\)\s*{/g,
      kind: "Function",
    },
    {
      regex: /(?:const|let|var)\s+(\w+)\s*=\s*\([^)]*\)\s*=>\s*{/g,
      kind: "Function",
    },
    {
      regex: /class\s+(\w+)(?:\s+extends\s+\w+)?\s*{/g,
      kind: "Class",
    },
  ];

  patterns.forEach((pattern) => {
    let match;
    while ((match = pattern.regex.exec(text)) !== null) {
      const name = match[1] || match[0].trim();
      const startPos = model.getPositionAt(match.index);

      // Find function body end position
      let endPos;
      if (match[0].includes("{")) {
        let openBraces = 1;
        let searchStartPos = match.index + match[0].length;

        for (let i = searchStartPos; i < text.length; i++) {
          if (text[i] === "{") openBraces++;
          else if (text[i] === "}") openBraces--;

          if (openBraces === 0) {
            endPos = model.getPositionAt(i + 1);
            break;
          }
        }
      }

      if (!endPos) {
        endPos = {
          lineNumber: startPos.lineNumber,
          column: model.getLineMaxColumn(startPos.lineNumber),
        };
      }

      result.push({
        name: name,
        kind: pattern.kind,
        range: {
          startLineNumber: startPos.lineNumber,
          startColumn: startPos.column,
          endLineNumber: endPos.lineNumber,
          endColumn: endPos.column,
        },
        children: [],
      });
    }
  });

  return result;
}
